﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

public partial class HexTextbox : TextBox
{
    private byte[] _bytes;
    public HexTextbox()
    {
        InitializeComponent();
    }
    private const int WM_CONTEXTMENU = 0x007b;//右键菜单消息 
    private const int WM_CHAR = 0x0102;       //输入字符消息（键盘输入的，输入法输入的好像不是这个消息）
    private const int WM_CUT = 0x0300;        //程序发送此消息给一个编辑框或combobox来删除当前选择的文本
    private const int WM_COPY = 0x0301;       //程序发送此消息给一个编辑框或combobox来复制当前选择的文本到剪贴板
    private const int WM_PASTE = 0x0302;      //程序发送此消息给editcontrol或combobox从剪贴板中得到数据
    private const int WM_CLEAR = 0x0303;      //程序发送此消息给editcontrol或combobox清除当前选择的内容；
    private const int WM_UNDO = 0x0304;        //程序发送此消息给editcontrol或combobox撤消最后一次操作

    #region 属性

    private int m_MaxByteLength = 0;
    [Description("获取或设置用户可在文本框控件中键入或粘贴的最大字节数。0 为允许无限长度。")]
    /// <summary>
    /// 获取或设置用户可在文本框控件中键入或粘贴的最大字节数。0 为允许无限长度。
    /// </summary>
    public int MaxByteLength
    {
        get { return m_MaxByteLength; }
        set { m_MaxByteLength = value; }
    }




    [Browsable(false)]
    /// <summary>
    /// 返回具有合法长度的文本, 此属性不会截断多字节字符
    /// </summary>
    public string RealText
    {
        get
        {
            if (m_MaxByteLength == 0)
            {
                return this.Text;
            }

            if (m_MaxByteLength*2 >= GetByteLength(this.Text))
            {
                return this.Text;
            }

            string text = this.Text;

            if (string.IsNullOrEmpty(text))
            {
                return text;
            }

            char[] c = text.ToCharArray();
            StringBuilder sb = new StringBuilder();
            int count = 0;

            for (int i = 0; i < c.Length; i++)
            {
                count += GetByteLength(c[i].ToString());
                if (m_MaxByteLength*2 >= count)
                {
                    sb.Append(c[i]);
                }
            }

            return sb.ToString();
        }
    }

    public byte[] Bytes {
        get
        {
                return DataEncoding.HexStringToBytes(this.Text.Replace(" ",""));
        }
        set
        {
            _bytes = value;
            if(_bytes!=null)
            base.Text = DataEncoding.BytesToHexString(_bytes);
        }    
    }

    #endregion

    /// <summary>
    /// 重写 WndProc
    /// </summary>
    protected override void WndProc(ref Message m)
    {
        //如果该属性没有设置，则允许输入
        if (m_MaxByteLength == 0)
        {
            base.WndProc(ref m);
            return;
        }

        switch (m.Msg)
        {
            case WM_CHAR:
                int i = (int)m.WParam;
                bool isBack = (i == (int)Keys.Back);
                bool isDelete = (i == (int)Keys.Delete);//实际上这是一个"."键
                bool isCtr = (i == 24) || (i == 22) || (i == 26) || (i == 3);

                if (isBack || isDelete || isCtr)
                {
                    //控制键不作处理
                }
                else
                {
                    char c = (char)i;
                    if (CheckByteLengthFlow(c.ToString()))
                    {
                        break;
                    }
                }
                base.WndProc(ref m);
                break;
            case WM_PASTE:
                IDataObject iData = Clipboard.GetDataObject();//取剪贴板对象
                if (iData.GetDataPresent(DataFormats.Text)) //判断是否是Text
                {
                    string text = (string)iData.GetData(DataFormats.Text);//取数据
                    if (CheckByteLengthFlow(text))
                    {
                        m.Result = (IntPtr)0;//不可以粘贴
                        break;
                    }
                }
                base.WndProc(ref m);
                break;
            default:
                base.WndProc(ref m);
                break;
        }
    }

    protected override void OnKeyPress(KeyPressEventArgs e)
    {
        base.OnKeyPress(e);
        //
        if ((e.KeyChar >= 'a' && e.KeyChar <= 'f') || (e.KeyChar >= 'A' && e.KeyChar <= 'F')
            || (e.KeyChar >= '0' && e.KeyChar <= '9')
            || e.KeyChar == 32 || e.KeyChar == 8 || e.KeyChar == 16)
        {
            // 转成大写
            e.KeyChar = char.ToUpper(e.KeyChar);
            e.Handled = false;
        }
        else
        {
            MessageBox.Show("请输入16进制字符【0-9,a-f,A-F】", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            //MessageBox.Show("请输入16进制字符");
            e.Handled = true;//阻拦字符键入
        }
        
    }

    protected override void OnTextChanged(EventArgs e)
    {
        base.OnTextChanged(e);
     
    }

    /// <summary>
    /// 判断即将输入的文本长度是否溢出
    /// </summary>
    /// <param name="text">文本</param>
    /// <returns>是否溢出</returns>
    private bool CheckByteLengthFlow(string text)
    {
        int len = GetByteLength(text);    //输入的字符的长度
        int tlen = GetByteLength(this.Text);  //文本框原有文本的长度
        int slen = GetByteLength(this.SelectedText);    //文本框选中文本的长度
        return (m_MaxByteLength*2 < (tlen - slen + len));
    }

    /// <summary>
    /// 计算文本字节长度，区分多字节字符
    /// </summary>
    /// <param name="text">文本</param>
    /// <returns>文本字节长度</returns>
    private int GetByteLength(string text)
    {
        return System.Text.Encoding.Default.GetBytes(text).Length;
    }

    private static bool IsOdd(int n)
    {
        return Convert.ToBoolean(n % 2);
    }

    protected override void OnLeave(EventArgs e)
    {
        base.OnLeave(e);
        if (IsOdd(this.Text.Replace(" ", "").Length))
        {
            this.Text = this.Text.Insert(this.Text.Length - 1, "0");
        }
    }
}
